plot(x = var.x,
y = var.y,
type = "tipus",
col = "color",
pch = "tipus de punt",
cex = "mida del punt",
lwd = "amplada de la línia",
main = "títol",
sub = "subtítol",
xlab = "nom de l'eix x",
ylab = "nom de l'eix y",
...)
plot(df$Sex, df$Age, main = "diagrama de caixes",
xlab = "sexe", ylab = "edat")
plot(df$RestBP, df$MaxHR, pch = 20, col = "red", cex = 2.5,
main = "diagrama de punts", xlab = "Rest Blood Pressure", ylab = "Max Heart Rate")
hist(df$Age, main = "histograma",xlab = "Edat")
library(ggplot2)
ggplot(df, aes(x = Sex, y = Chol, colour = AHD)) +
geom_boxplot()
Ho mirem en el plot:
ggplot(df, # liver és el nom del dataframe
aes(x = Sex, # Variable en l'eix x
y = Chol, # Variable en l'eix y
colour = AHD # Color: alerta, perquè el color crea grups!
)) + # fixeu-vos en el signe "+" per afegir més comandes a la instrucció
geom_boxplot() # geom_alguna_cosa() crea el tipus de plot que vulguem, en aquest cas un boxplot. Per saber els tipus de plots que hi ha podem anar a https://ggplot2.tidyverse.org/reference/
Un altre exemple:
df %>%
ggplot(aes(Age, RestBP, colour = AHD)) +
geom_point()
geom_point() veiem que ens fa gràfics de punts, els adequats quan tenim dues variables contínues.
Fixeu-vos que aquí hem fet servir la pipe.
En lloc dels boxplots, potser volem els violin plots:
ggplot(df, aes(x = Sex, y = RestBP, colour = AHD)) +
geom_violin() +
theme_bw() +
labs(title = "Violin plot, que són molt monos",
subtitle = "I aquí hi va un subtítol si volem") +
xlab("Gènere") +
ylab("Ritme cardíac en repòs")
ggplot(df, aes(x = Sex, y = RestBP, colour = AHD, fill = AHD)) +
geom_violin(alpha = 0.7) + # aquesta alpha fa que el color no sigui sòlid
theme_bw() +
labs(title = "Violin plot, que són molt monos",
subtitle = "I aquí hi va un subtítol si volem") +
xlab("Gènere") +
ylab("Ritme cardíac en repòs")
A partir d’aquí hi ha moltíssimes maneres de personalitzar un diagrama:
ggplot(df, aes(x = Age, y = MaxHR, colour = AHD, shape = Sex)) +
geom_point(size=1.5) +
labs(title = "Gràfic puc útil",
subtitle = "Però molt fàcil de fer") +
xlab("Edat") +
ylab("Batecs per minut màxims") +
geom_smooth(method = "lm", se = FALSE)
Fixeu-vos que colour i shape em creen “grups”, és a dir, que quan li demano que em faci rectes (geom_smooth), me les fa segons els grups que li he fet crear a aes. Això és molt important!
Veieu però que aquest gràfic és bastant horrible perquè hem volgut posar massa informació a la vegada. Ho podem separar de forma fàcil amb facet_wrap:
ggplot(df, aes(x = Age, y = MaxHR, colour = AHD)) +
geom_point(size=1.5) +
facet_wrap(~ Sex) + # Fixeu-vos amb la titlla per dir "en funció de"
labs(title = "Gràfic més útil") +
xlab("Edat") +
ylab("Batecs per minut màxims") +
geom_smooth(method = "lm", se = FALSE)
Bastant millor! Ara per exemple veig que a les dones que tenen AHD els puja els batecs per minut màxims amb l’edat. Això no té bona pinta!
Paletes de colors:
Imaginem que tinc aquest gràfic, que faig amb les dades de contaminació:
library(readr)
library(tidyr)
library(lubridate)
library(glue)
cont <- read_csv("input/contaminacio.csv", locale = locale(encoding="latin1")) %>%
select(data, municipi, contaminant, unitats, starts_with("h")) %>%
mutate(contaminant = glue("{contaminant} ({unitats})")) %>%
pivot_longer(starts_with("h")) %>%
drop_na() %>%
mutate(Mes = month(floor_date(data, "month"), label = T, abbr = F)) %>%
group_by(municipi, contaminant, Mes) %>%
summarise(Mitjana = mean(value)) %>%
ungroup() %>%
mutate(across(where(is.character), as.factor))
Les dades estan així:
glimpse(cont)
## Rows: 204
## Columns: 4
## $ municipi <fct> Reus, Reus, Reus, Reus, Reus, Reus, Reus, Reus, Reus, Reus~
## $ contaminant <fct> CO (mg/m3), CO (mg/m3), CO (mg/m3), CO (mg/m3), CO (mg/m3)~
## $ Mes <ord> gener, febrer, març, abril, maig, juny, juliol, agost, set~
## $ Mitjana <dbl> 0.2632612, 0.2777778, 0.2203893, 0.2254167, 0.2036339, 0.2~
Fem un gràfic per cada ciutat:
cont %>%
ggplot(aes(x = Mes, y = Mitjana, colour = contaminant, group = contaminant)) +
geom_line() +
facet_wrap(~ municipi) + # Fixeu-vos amb la titlla per dir "en funció de"
labs(title = "Gràfic de contaminació") +
xlab("") +
ylab("Contaminació en les seves unitats")
No està malament, però els colors són una mica lletjos i com que són colors de contaminació, busquem colors que siguin més tètrics. Podem buscar una paleta de colors que estigui bé aquí i aquí (i altres llocs si busqueu). En aquest segon link veiem que hi ha una paleta que es diu inferno (del paquet viridis, que és un paquet de colors només) i com que això de la contaminació és bastant infernal, sembla adequat.
Agafem els colors d’aquesta paleta amb la funció inferno que té un paràmetre, que és el nombre de colors que volem (així els espaiarà correctament):
paleta <- viridis::inferno(length(unique(cont$contaminant)))
Li diem al nostre gràfic que faci servir aquests colors:
cont %>%
ggplot(aes(x = Mes, y = Mitjana, colour = contaminant, group = contaminant)) +
geom_line() +
facet_wrap(~ municipi) + # Fixeu-vos amb la titlla per dir "en funció de"
labs(title = "Gràfic de contaminació") +
xlab("") +
ylab("Contaminació en les seves unitats") +
scale_color_manual(values = paleta)
Molt millor!
Com a recurs, també hi ha el paquet RColorBrewer, que té paletes útils. I també podem crear la nostra. Fixeu-vos que la paleta és simplement un vector de colors en format hexagesimal:
paleta
## [1] "#000004FF" "#1B0C42FF" "#4B0C6BFF" "#781C6DFF" "#A52C60FF" "#CF4446FF"
## [7] "#ED6925FF" "#FB9A06FF" "#F7D03CFF" "#FCFFA4FF"
Per tant res ens impedeix de crear un vector amb els colors que ens agradin i posar-los on vulguem.
Els colors de les línies no són les úniques coses que són lletjotes dels gràfics. Les estètiques així més generals els retoquem amb la funció theme(). Per exemple, ens agradaria posar els noms dels mesos en diagonal perquè es vegin bé, evidentment ningú se sap la comanda per fer això, així que ho busquem a stackoverflow i trobem que podem fer:
cont %>%
ggplot(aes(x = Mes, y = Mitjana, colour = contaminant, group = contaminant)) +
geom_line() +
facet_wrap(~ municipi) + # Fixeu-vos amb la titlla per dir "en funció de"
labs(title = "Gràfic de contaminació") +
xlab("") +
ylab("Contaminació en les seves unitats") +
scale_color_manual(values = paleta) +
theme(axis.text.x = element_text(angle = 45,hjust=1))
Molt bé! Ara veig que no hem capitalitzat els noms; ho fem en un moment (puc aprofitar la pipe!)
ordre_mesos <- stringr::str_to_title(levels(cont$Mes))
cont %>%
mutate(
Mes = stringr::str_to_title(Mes),
# Asseguro que quan els capitalitzo no es desordenin
Mes = forcats::fct_relevel(Mes, ordre_mesos)
) %>%
ggplot(aes(x = Mes, y = Mitjana, colour = contaminant, group = contaminant)) +
geom_line() +
facet_wrap(~ municipi) + # Fixeu-vos amb la titlla per dir "en funció de"
labs(title = "Gràfic de contaminació") +
xlab("") +
ylab("Contaminació en les seves unitats") +
scale_color_manual(values = paleta) +
theme(axis.text.x = element_text(angle = 45,hjust=1))
Volem canviar també el títol de la llegenda per posar-lo en majúscula, fem servir la funció guides() (guide = llegenda):
cont %>%
mutate(
Mes = stringr::str_to_title(Mes),
# Asseguro que quan els capitalitzo no es desordenin
Mes = forcats::fct_relevel(Mes, ordre_mesos)
) %>%
ggplot(aes(x = Mes, y = Mitjana, colour = contaminant, group = contaminant)) +
geom_line() +
facet_wrap(~ municipi) + # Fixeu-vos amb la titlla per dir "en funció de"
labs(title = "Gràfic de contaminació") +
xlab("") +
ylab("Contaminació en les seves unitats") +
scale_color_manual(values = paleta) +
theme(axis.text.x = element_text(angle = 45,hjust=1)) +
guides(colour=guide_legend(title = "Contaminant"))
També hi ha temes complets, per no haver d’anar canviat les coses una a una, els podeu trobar aquí.
A mi el que m’agrada més és el theme_bw()
cont %>%
mutate(
Mes = stringr::str_to_title(Mes),
# Asseguro que quan els capitalitzo no es desordenin
Mes = forcats::fct_relevel(Mes, ordre_mesos)
) %>%
ggplot(aes(x = Mes, y = Mitjana, colour = contaminant, group = contaminant)) +
geom_line() +
facet_wrap(~ municipi) + # Fixeu-vos amb la titlla per dir "en funció de"
labs(title = "Gràfic de contaminació") +
xlab("") +
ylab("Contaminació en les seves unitats") +
scale_color_manual(values = paleta) +
theme(axis.text.x = element_text(angle = 45,hjust=1)) +
guides(colour=guide_legend(title = "Contaminant")) +
theme_bw()
Molt millor, però ens ha desaparegut lo dels noms de costat. Això és perquè els temes completes a vegades sobreescriuren les coses que nosaltres haguem posat a theme() (perquè ells també estan tocant theme). En aquest cas l’únic que hem de fer és canviar l’ordre:
cont %>%
mutate(
Mes = stringr::str_to_title(Mes),
# Asseguro que quan els capitalitzo no es desordenin
Mes = forcats::fct_relevel(Mes, ordre_mesos)
) %>%
ggplot(aes(x = Mes, y = Mitjana, colour = contaminant, group = contaminant)) +
geom_line() +
facet_wrap(~ municipi) + # Fixeu-vos amb la titlla per dir "en funció de"
labs(title = "Gràfic de contaminació") +
xlab("") +
ylab("Contaminació en les seves unitats") +
scale_color_manual(values = paleta) +
theme_bw() +
theme(axis.text.x = element_text(angle = 45,hjust=1)) +
guides(colour=guide_legend(title = "Contaminant"))
Ja tenim un gràfic prou decent, però ara el veig petit. Per veure’l més gran al markdown hem de tocar la configuració del chunk. per exemple, podem posar out.widht=“100%” (fixeu-vos amb les cometes) perquè ocupi tota l’amplada.
cont %>%
mutate(
Mes = stringr::str_to_title(Mes),
# Asseguro que quan els capitalitzo no es desordenin
Mes = forcats::fct_relevel(Mes, ordre_mesos)
) %>%
ggplot(aes(x = Mes, y = Mitjana, colour = contaminant, group = contaminant)) +
geom_line() +
facet_wrap(~ municipi) + # Fixeu-vos amb la titlla per dir "en funció de"
labs(title = "Gràfic de contaminació") +
xlab("") +
ylab("Contaminació en les seves unitats") +
scale_color_manual(values = paleta) +
theme_bw() +
theme(axis.text.x = element_text(angle = 45,hjust=1)) +
guides(colour=guide_legend(title = "Contaminant"))
Plotly és una “nova” llibreria que tranforma els gràfics a javascript i html i per tant són interactius (com si fossin una pàgina web). Es pot utilitzar tant en R com en python i s’està fent molt famosa perquè es poden fer gràfics interactius de forma molt simple.
No és tan potent (a nivell de quantitat de coses que es poden fer) com ggplot2.
Veiem un exemple:
library(plotly)
plot_ly(data = iris, x = ~Sepal.Length, y = ~Petal.Length)
Fixeu-vos que teniu comandes per fer zoom, baixar-ho en png, etc.
Fixeu-vos que la forma de les comandes és semblant però aquí fem servir la titlla davant de cada variable.
Coloregem segons el tipus de plantes:
plot_ly(data = iris, x = ~Sepal.Length, y = ~Petal.Length, color = ~Species)
També es poden fer servir colors de paletes, per exemple la Spectral de la ColorBrewer:
plot_ly(data = iris, x = ~Sepal.Length, y = ~Petal.Length, color = ~Species, colors = "Spectral")
Un altre exemple, amb les dades de covid:
start <- lubridate::today() - 30
p <- "https://analisi.transparenciacatalunya.cat/resource/jj6z-iyrp.json"
# Fixeu-vos amb les cometes simples de l'start! Això és perquè lo que passarà aquí
# dins en el fons és un string i el Socrata ho ha de saber
q <- glue::glue("?$where= data > '{start}'")
covid <- RSocrata::read.socrata(glue::glue(p, q)) %>%
# Treu totes les columnes que acaben amb "codi" (evidentment,
# ho podem fer llistant-les una per una també) i treu també
# el nom del districte
select(-c(ends_with("codi"), districtedescripcio)) %>%
mutate(
# Converteix el número de casos a numèric
numcasos = as.numeric(numcasos),
# I tota la resta (que encara son caràcters) a factor
across(where(is.character), as.factor)
)
Les sumo totes i faig un gràfic d’evolució:
covid %>%
group_by(data) %>%
summarise(Total_casos = sum(numcasos)) %>%
plot_ly(x = ~ data, y = ~ Total_casos, type = 'scatter', mode = 'lines+markers')
Es poden fer coses més complicades amb la funció add_trace. Per exemple, vull afegir les vacunes, que també trec de dades obertes:
p <- "https://analisi.transparenciacatalunya.cat/resource/irki-p3c7.json"
q <- glue::glue("?$where= data > '{start}'")
vac <- RSocrata::read.socrata(glue::glue(p, q)) %>%
# Treu totes les columnes que acaben amb "codi" (evidentment,
# ho podem fer llistant-les una per una també) i treu també
# el nom del districte
select(-c(ends_with("CODI"), districte)) %>%
mutate(
# Converteix el número de casos a numèric
recompte = as.numeric(recompte),
# I tota la resta (que encara son caràcters) a factor
across(where(is.character), as.factor)
)
tot <- covid %>%
inner_join(vac, by = c("data" = "data", "municipidescripcio" = "municipi")) %>%
group_by(data) %>%
summarise(Total_casos = sum(numcasos), Total_vacunes = sum(recompte))
fig <- plot_ly(tot, x = ~data, y = ~Total_casos, name = 'Casos totals',
type = 'scatter', mode = 'lines+markers')
fig <- fig %>% add_trace(y = ~Total_vacunes, name = 'Vacunes totals', mode = 'lines+markers')
fig
Potser volem posar les vacunes en un segon eix, es fa amb la funció layout i l’argument yaxis:
fig <- plot_ly(tot, x = ~data, y = ~Total_casos, name = 'Casos totals',
type = 'scatter', mode = 'lines+markers')
fig <- fig %>% add_trace(y = ~Total_vacunes, name = 'Vacunes totals', mode = 'lines+markers', yaxis = "y2")
fig <- fig %>% layout(yaxis2 = list(overlaying = "y", side = "right"))
fig
Tot i que, com veieu, això no és molt recomanable.
Potser millor afegir les vacunes com a barres? També es pot fer:
fig <- plot_ly(tot, x = ~data, y = ~Total_casos, name = 'Casos totals',
type = 'scatter', mode = 'lines+markers')
fig <- fig %>% add_trace(y = ~Total_vacunes, name = 'Vacunes totals', type = 'bar', yaxis = "y2", opacity=0.6)
fig <- fig %>% layout(yaxis2 = list(overlaying = "y", side = "right"))
fig
També tenim l’opció de convertir un gràfic de ggplot a plotly:
pl <- cont %>%
mutate(
Mes = stringr::str_to_title(Mes),
# Asseguro que quan els capitalitzo no es desordenin
Mes = forcats::fct_relevel(Mes, ordre_mesos)
) %>%
ggplot(aes(x = Mes, y = Mitjana, colour = contaminant, group = contaminant)) +
geom_line() +
facet_wrap(~ municipi) + # Fixeu-vos amb la titlla per dir "en funció de"
labs(title = "Gràfic de contaminació") +
xlab("") +
ylab("Contaminació en les seves unitats") +
scale_color_manual(values = paleta) +
theme_bw() +
theme(axis.text.x = element_text(angle = 45,hjust=1)) +
guides(colour=guide_legend(title = "Contaminant"))
ggplotly(pl)
Fixeu-vos però que no canvia els eixos quan fem desaparèixer línies; el podem fer originalment amb plotly fent servir la funció group_map de dplyr i subplot de plotly:
cont %>%
mutate(
Mes = stringr::str_to_title(Mes),
# Asseguro que quan els capitalitzo no es desordenin
Mes = forcats::fct_relevel(Mes, ordre_mesos)
) %>%
# Hem d'agrupar *abans* del gràfic perquè plotly ja vol veure
# les dades agrupades en els grups que sortiran en el gràfic
group_by(municipi) %>%
group_map(~ plot_ly(data=., x = ~Mes, y = ~Mitjana, color = ~contaminant,
type = "scatter", mode="lines"), keep=TRUE) %>%
subplot(nrows = 1, shareX = TRUE, shareY=TRUE)